package com.amose.factory;

import com.amose.config.Configuration;
import com.amose.config.MapperStatement;
import com.amose.model.SqlInfo;
import com.amose.utils.GenericTokenParser;
import com.amose.utils.HumpUtil;
import com.amose.utils.ParameterMapping;
import com.amose.utils.ParameterMappingTokenHandler;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author yangpeng
 * @time 2020/2/22
 * @since 1.0.0
 */
public class SimpleExecutor implements Executor {
    @Override
    public <T> List<T> queryList(Configuration configuration, MapperStatement mapperStatement, Object... params) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
        //获取连接
        Connection conn = configuration.getDataSource().getConnection();
        //解析sqlText
        SqlInfo sqlInfo = getSqlInfo(mapperStatement.getSqlText());
        //注入参数
        PreparedStatement ps = conn.prepareStatement(sqlInfo.getSql());
        String paramType = mapperStatement.getParamType();
        Class<?> paramTypeClass = getClassType(paramType);

        List<ParameterMapping> parameterMappingList = sqlInfo.getParameterMappingList();
        for(int i = 0 ; i < parameterMappingList.size(); i++){
            String content = parameterMappingList.get(i).getContent();
            Field field = paramTypeClass.getDeclaredField(content);
            field.setAccessible(true);
            ps.setObject(i+1,field.get(params[0]));
        }
        //执行sql
        ResultSet resultSet = ps.executeQuery();
        //解析结果集
        String resultType = mapperStatement.getResultType();
        Class<?> resultTypeObject = getClassType(resultType);
        List<T> list = new ArrayList<>();
        while(resultSet.next()){
            //读取列元数据信息
            Object resultObject = resultTypeObject.newInstance();
            ResultSetMetaData metaData = resultSet.getMetaData();
            for(int i = 1 ; i <= metaData.getColumnCount();i++){
                String columnName = metaData.getColumnName(i);
                Object value = resultSet.getObject(columnName);
                columnName = HumpUtil.lineToHump(columnName);
                Field field = resultTypeObject.getDeclaredField(columnName);
                field.setAccessible(true);
                field.set(resultObject,value);
            }
            list.add((T) resultObject);
        }
        return list;
    }

    private Class<?> getClassType(String paramType) throws ClassNotFoundException {
        if(paramType == null || "".equals(paramType)){
            return null;
        }
        return Class.forName(paramType);
    }

    private SqlInfo getSqlInfo(String sqlText) {
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{","}",parameterMappingTokenHandler);
        String sql = genericTokenParser.parse(sqlText);
        SqlInfo sqlInfo = new SqlInfo();
        sqlInfo.setSql(sql);
        sqlInfo.setParameterMappingList(parameterMappingTokenHandler.getParameterMappings());
        return sqlInfo;
    }

    @Override
    public <T> T queryOne(Configuration configuration, MapperStatement mapperStatement, Object... params) throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        List<Object> list = queryList(configuration, mapperStatement, params);
        if(list.size() == 1){
            return (T) list.get(0);
        }
        return null;
    }

    @Override
    public int update(Configuration configuration, MapperStatement mapperStatement, Object... params) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        //获取连接
        Connection conn = configuration.getDataSource().getConnection();
        //解析sqlText
        SqlInfo sqlInfo = getSqlInfo(mapperStatement.getSqlText());
        //注入参数
        PreparedStatement ps = conn.prepareStatement(sqlInfo.getSql());
        String paramType = mapperStatement.getParamType();
        Class<?> paramTypeClass = getClassType(paramType);
        List<ParameterMapping> parameterMappingList = sqlInfo.getParameterMappingList();
        for(int i = 0 ; i < parameterMappingList.size(); i++){
            String content = parameterMappingList.get(i).getContent();
            Field field = paramTypeClass.getDeclaredField(content);
            field.setAccessible(true);
            ps.setObject(i+1,field.get(params[0]));
        }
        //执行sql
        int result = ps.executeUpdate();
        return result;
    }
}
